﻿using System;
using System.Collections.Generic;
using System.Numerics;
using System.Text;

namespace ttbit.core
{
    public static class Mat3
    {
        public static float[] Create()
        {
            var mat = new float[9];
            mat.Mat3Init();
            return mat;
        }
        //GL左下角为0点，RT的时候需要按0点输出，屏幕则是反的
        public static void Mat3Proj(this float[] mat, int width, int height, bool InvertY)
        {
            float sy = InvertY ? -1.0f : 1.0f;
            mat[3 * 0 + 0] = 2.0f / width;
            mat[3 * 0 + 1] = 0;
            mat[3 * 0 + 2] = -1;

            mat[3 * 1 + 0] = 0;
            mat[3 * 1 + 1] = sy * 2.0f / height;
            mat[3 * 1 + 2] = -1 * sy;

            mat[3 * 2 + 0] = 0;
            mat[3 * 2 + 1] = 0;
            mat[3 * 2 + 2] = 1;
        }


        /// <summary>
        /// 初始化方法
        /// </summary>
        /// <param name="mat"></param>
        public static void Mat3Init(this float[] mat)
        {
            mat[3 * 0 + 0] = 1;
            mat[3 * 0 + 1] = 0;
            mat[3 * 0 + 2] = 0;

            mat[3 * 1 + 0] = 0;
            mat[3 * 1 + 1] = 1;
            mat[3 * 1 + 2] = 0;

            mat[3 * 2 + 0] = 0;
            mat[3 * 2 + 1] = 0;
            mat[3 * 2 + 2] = 1;

        }
        public static void Mat3CopyFrom(this float[] mat, float[] other)
        {
            for (var i = 0; i < 9; i++)
            {
                mat[i] = other[i];
            }
        }
        public static void Mat3CopyFrom(this float[] mat, Matrix3x2 other)
        {
            mat[3 * 0 + 0] = other.M11;
            mat[3 * 1 + 0] = other.M12;
            mat[3 * 0 + 1] = other.M21;
            mat[3 * 1 + 1] = other.M22;
            mat[3 * 0 + 2] = other.M31;
            mat[3 * 1 + 2] = other.M32;

            mat[3 * 2 + 0] = 0;
            mat[3 * 2 + 1] = 0;
            mat[3 * 2 + 2] = 1;
        }

        public static float[] Mat3Clone(this float[] mat)
        {
            return mat.Clone() as float[];

        }
        //public static void Mat2x3Init(this float[] mat)
        //{
        //    mat[3 * 0 + 0] = 1;
        //    mat[3 * 0 + 1] = 0;
        //    mat[3 * 0 + 2] = 0;

        //    mat[3 * 1 + 0] = 0;
        //    mat[3 * 1 + 1] = 1;
        //    mat[3 * 1 + 2] = 0;
        //}
        public static void Mat3GenRot(this float[] mat, float angle)
        {

            var s = MathF.Sin(angle);
            var c = MathF.Cos(angle);


            mat[3 * 0 + 0] = c;
            mat[3 * 0 + 1] = -s;
            mat[3 * 0 + 2] = 0;

            mat[3 * 1 + 0] = s;
            mat[3 * 1 + 1] = c;
            mat[3 * 1 + 2] = 0;

            mat[3 * 2 + 0] = 0;
            mat[3 * 2 + 1] = 0;
            mat[3 * 2 + 2] = 1;

        }
        public static void Mat3GenScale(this float[] mat, float scaleX, float scaleY)
        {
            mat[3 * 0 + 0] = scaleX;
            mat[3 * 0 + 1] = 0;
            mat[3 * 0 + 2] = 0;

            mat[3 * 1 + 0] = 0;
            mat[3 * 1 + 1] = scaleY;
            mat[3 * 1 + 2] = 0;

            mat[3 * 2 + 0] = 0;
            mat[3 * 2 + 1] = 0;
            mat[3 * 2 + 2] = 1;
        }
        public static void Mat3GenTran(this float[] mat, float x, float y)
        {



            mat[3 * 0 + 0] = 1;
            mat[3 * 0 + 1] = 0;
            mat[3 * 0 + 2] = x;

            mat[3 * 1 + 0] = 0;
            mat[3 * 1 + 1] = 1;
            mat[3 * 1 + 2] = y;

            mat[3 * 2 + 0] = 0;
            mat[3 * 2 + 1] = 0;
            mat[3 * 2 + 2] = 1;

        }
        public static void Mat3GenTRS(this float[] outmat, Vector2 tran, float rotate, Vector2 scale)
        {
            var matt = Mat3.Create();
            matt.Mat3GenTran(tran.X, tran.Y);

            var matr = Mat3.Create();
            matr.Mat3GenRot(rotate);
            var mats = Mat3.Create(); 
            mats.Mat3GenScale(scale.X, scale.Y);


            outmat.Mat3GenTran(tran.X, tran.Y);//平移
            outmat.Mat3Mul(matr);//旋转
            outmat.Mat3Mul(mats);//缩放

            ////var outmat = Mat3.Create();
            //outmat.Mat3GenScale(scale.X, scale.Y);//先缩放
            //outmat.Mat3Mul(matr);//再旋转
            //outmat.Mat3Mul(matt);//再平移
        }

        //运算方法
        public static void Mat3Mul(this float[] mat, float[] matb)
        {
            var l11 = matb[3 * 0 + 0];
            var l12 = matb[3 * 0 + 1];
            var l13 = matb[3 * 0 + 2];
            var l21 = matb[3 * 1 + 0];
            var l22 = matb[3 * 1 + 1];
            var l23 = matb[3 * 1 + 2];
            var l31 = matb[3 * 2 + 1];
            var l32 = matb[3 * 2 + 1];
            var l33 = matb[3 * 2 + 2];

            var r11 = mat[3 * 0 + 0];
            var r12 = mat[3 * 0 + 1];
            var r13 = mat[3 * 0 + 2];
            var r21 = mat[3 * 1 + 0];
            var r22 = mat[3 * 1 + 1];
            var r23 = mat[3 * 1 + 2];
            var r31 = mat[3 * 2 + 0];
            var r32 = mat[3 * 2 + 1];
            var r33 = mat[3 * 2 + 2];
            //for (int i = 0; i < 3; i++)
            //{
            //    for (int j = 0; j < 3; j++)
            //    {
            //        for (int k = 0; k < 3; k++)
            //        {
            //            result[i][j] += (matrix1[i][k] * matrix2[k][j]);
            //        }
            //    }

            mat[3 * 0 + 0] = l11 * r11 + l12 * r21 + l13 * r31;
            mat[3 * 0 + 1] = l11 * r12 + l12 * r22 + l13 * r32;
            mat[3 * 0 + 2] = l11 * r13 + l12 * r23 + l13 * r33;
            mat[3 * 1 + 0] = l21 * r11 + l22 * r21 + l23 * r31;
            mat[3 * 1 + 1] = l21 * r12 + l22 * r22 + l23 * r32;
            mat[3 * 1 + 2] = l21 * r13 + l22 * r23 + l23 * r33;
            mat[3 * 2 + 0] = l31 * r11 + l32 * r21 + l33 * r31;
            mat[3 * 2 + 1] = l31 * r12 + l32 * r22 + l33 * r32;
            mat[3 * 2 + 2] = l31 * r13 + l32 * r23 + l33 * r33;
        }
        //需指出这个方式是不能用于一些特殊的矩阵的，比如推成斜面，但我们显然不需要这些特殊的情况，即使需要，大不了用Matrix4x4转一下
        public static Matrix3x2 ToMatrix3x2(this float[] mat)
        {
            var matrix = System.Numerics.Matrix3x2.Identity;
            var M11 = mat[3 * 0 + 0];
            var M21 = mat[3 * 0 + 1];
            var M31 = mat[3 * 0 + 2];
            var M12 = mat[3 * 1 + 0];
            var M22 = mat[3 * 1 + 1];
            var M32 = mat[3 * 1 + 2];
            return new Matrix3x2(M11, M12, M21, M22, M31, M32);
        }

        public static void Mat3Invert(this float[] mat)
        {
            //需指出这个方式是不能用于一些特殊的矩阵的，比如推成斜面，但我们显然不需要这些特殊的情况，即使需要，大不了用Matrix4x4转一下
            var matrix = ToMatrix3x2(mat);
            Matrix3x2.Invert(matrix, out Matrix3x2 m2);
            Mat3CopyFrom(mat, m2);




        }

    }
}
